/*
 * Group 3, User Interface Programming II (vt11)
 * Pooya | Flora | Monica | Can
 */
package vical.view;

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.util.Calendar;
import java.util.List;
import javax.swing.JPanel;
import vical.model.DayCardModel;
import vical.model.MonthModel;
import java.util.ArrayList;
import java.util.Random;
import vical.utility.AnimationDriver;

/*
 * The monthView, use a month-calendar to show the entries.
 * The calendar is consisted of many DayCards.
 *
 * @author Can
 */
public class MonthView extends AbstractView {

    private MonthModel model;
    private ViewPanel viewPanel;
    private DayCard selectedDayCard;
    // components
    private WeekBar weekBar;
    private JPanel monthPanel;
    private ArrayList<DayCard> dayCards;

    public MonthView(ViewPanel viewPanel) {
        this.model = new MonthModel();
        this.viewPanel = viewPanel;
        this.initComponents();
        this.doAnimation();
    }

    public MonthView(ViewPanel viewPanel, MonthModel mm) {
        this.model = mm;
        this.viewPanel = viewPanel;
        this.initComponents();
        this.doAnimation();
    }

    private void doAnimation() {
        Runnable r = new Runnable() {

            public void run() {
                try {
                    flashDayCards();
                } catch (Exception x) {
                    System.out.println(this.getClass() + ": " + x.getLocalizedMessage());
                }
            }
        };
        Thread animation = new Thread(r);
        animation.start();
    }

    private void flashDayCards() {
        List<DayCard> tmpDayCards = new ArrayList<DayCard>();
        for (DayCard dayCard : dayCards) {
            tmpDayCards.add(dayCard);
        }
        Random randomBase = new Random();
        while (!tmpDayCards.isEmpty()) {
            int randomIndex = randomBase.nextInt(tmpDayCards.size());
            DayCard dayCard = tmpDayCards.get(randomIndex);
            try {
                AnimationDriver.flash(dayCard, 30);
                Thread.sleep(20);
                AnimationDriver.flash(dayCard, 30);
                Thread.sleep(20);
            } catch (InterruptedException x) {
                Thread.currentThread().interrupt();
                System.out.println(x.getLocalizedMessage());
            }
            tmpDayCards.remove(randomIndex);
        }
    }

    private void doTwinkle() {
        Runnable r = new Runnable() {

            public void run() {
                try {
                    twinkleDayCards();
                } catch (Exception x) {
                    System.out.println(this.getClass() + "@: " + x.toString());
                }
            }
        };
        Thread animation = new Thread(r);
        animation.start();
    }

    private void twinkleDayCards() {
        List<DayCard> tmpDayCards = new ArrayList<DayCard>();
        for (DayCard dayCard : dayCards) {
            tmpDayCards.add(dayCard);
        }
        Random randomBase = new Random();
        while (!tmpDayCards.isEmpty()) {
            int randomIndex = randomBase.nextInt(tmpDayCards.size());
            DayCard dayCard = tmpDayCards.get(randomIndex);
            try {
                AnimationDriver.Shine(dayCard);
                Thread.sleep(500);
            } catch (InterruptedException x) {
                Thread.currentThread().interrupt();
            }
            tmpDayCards.remove(randomIndex);
        }
    }

    private void initComponents() {
        weekBar = new WeekBar();
        monthPanel = new JPanel();

        dayCards = new ArrayList<DayCard>();

        this.setLayout(new BorderLayout());
        this.add(BorderLayout.NORTH, weekBar);
        this.add(BorderLayout.CENTER, monthPanel);

        updateComponents();
    }

    private void updateComponents() {
        monthPanel.removeAll();
        int rowsCount = model.getRowsCount();
        int columnsCount = model.getColumnsCount();
        monthPanel.setLayout(new GridLayout(rowsCount, columnsCount));

        // fill the day cards
        dayCards.clear();
        for (DayCardModel dayCardModel : this.model.getDayCardModels()) {
            dayCardModel.updateEntries();

            DayCard dc = new DayCard(dayCardModel, this);
            dayCards.add(dc);

            monthPanel.add(dc);
        }
    }

    public void next() {
        this.model.nextMonth();
        refresh();
        this.doAnimation();
    }

    public void previous() {
        this.model.previousMonth();
        refresh();
        this.doAnimation();
    }

    public void today() {
        this.jumpToDate(Calendar.getInstance());
    }

    public void resetDayCards() {
        for (DayCard dc : dayCards) {
            dc.setSelected(false);
        }
    }

    public void selectDayCard(DayCard dayCard) {
        if (selectedDayCard != null) {
            selectedDayCard.setSelected(false);
        }
        selectedDayCard = dayCard;
        selectedDayCard.setSelected(true);
    }

    @Override
    public void refresh() {
        this.updateComponents();
        this.repaint();
        this.revalidate();
    }

    @Override
    public String getCaption() {
        return model.getMonthString() + " " + Integer.toString(model.getYear());
    }

    @Override
    public void jumpToDate(Calendar cal) {
        int year = cal.get(Calendar.YEAR);
        int month = cal.get(Calendar.MONTH);
        if (year == this.model.getYear() && month == this.model.getMonth()) {
            return;
        }
        this.model.jumpToDate(year, month);
        this.refresh();
        this.doAnimation();
    }

    public void notifyEntryChanged() {
        viewPanel.refreshLeftPanel();
        for (DayCardModel dayCardModel : this.model.getDayCardModels()) {
            dayCardModel.updateEntries();
        }
    }

    @Override
    public void highlightEntriesByCategory(String category) {
        for (DayCard dc : dayCards) {
            dc.highlightEntryiesByCategory(category);
        }
    }

    @Override
    public void showEntriesByCategories(List<String> categories) {
        this.model.setCategoriesFilter(categories);
        this.refresh();
    }

    @Override
    public void showEntriesByPriorities(ArrayList<String> priorities) {
        this.model.setPrioritiesFilter(priorities);
        this.refresh();
    }
}
